+2005-01-12 Tor Lillqvist <tlillqvist@novell.com>
+
+ Fix for #162790, by Iwan Wong:
+
+ * gdk/win32/gdkdrawable-win32.c: Implement dashed lines
+ correctly. Simplify the interface to render_line_horizontal() and
+ render_line_vertical(). Need to draw lines "manually" also on
+ NT-based Windowses if we have a dash offset or are drawing
+ double-dashed lines.
+
+ * gdk/win32/gdkprivate-win32.h: Keep also the dash offset,
+ double-dash flag, and a brush for the background colour (used by
+ the odd dashes in the double-dash line style) in the GdkGCWin32
+ struct.
+
+ * gdk/win32/gdkgc-win32.c: Set up above new fields.
+
2005-01-10 Federico Mena Quintero <federico@ximian.com>
Fix #162617.
+2005-01-12 Tor Lillqvist <tlillqvist@novell.com>
+
+ Fix for #162790, by Iwan Wong:
+
+ * gdk/win32/gdkdrawable-win32.c: Implement dashed lines
+ correctly. Simplify the interface to render_line_horizontal() and
+ render_line_vertical(). Need to draw lines "manually" also on
+ NT-based Windowses if we have a dash offset or are drawing
+ double-dashed lines.
+
+ * gdk/win32/gdkprivate-win32.h: Keep also the dash offset,
+ double-dash flag, and a brush for the background colour (used by
+ the odd dashes in the double-dash line style) in the GdkGCWin32
+ struct.
+
+ * gdk/win32/gdkgc-win32.c: Set up above new fields.
+
2005-01-10 Federico Mena Quintero <federico@ximian.com>
Fix #162617.
+2005-01-12 Tor Lillqvist <tlillqvist@novell.com>
+
+ Fix for #162790, by Iwan Wong:
+
+ * gdk/win32/gdkdrawable-win32.c: Implement dashed lines
+ correctly. Simplify the interface to render_line_horizontal() and
+ render_line_vertical(). Need to draw lines "manually" also on
+ NT-based Windowses if we have a dash offset or are drawing
+ double-dashed lines.
+
+ * gdk/win32/gdkprivate-win32.h: Keep also the dash offset,
+ double-dash flag, and a brush for the background colour (used by
+ the odd dashes in the double-dash line style) in the GdkGCWin32
+ struct.
+
+ * gdk/win32/gdkgc-win32.c: Set up above new fields.
+
2005-01-10 Federico Mena Quintero <federico@ximian.com>
Fix #162617.
/* Drawing
*/
-/*
- * Render a dashed line 'by hand' cause the Win9x GDI is
- * too limited to do so
+static DWORD default_double_dashes[] = { 3, 3 };
+
+/* Render a dashed line 'by hand'. Used for all dashes on Win9x (where
+ * GDI is way too limited), and for double dashes on all Windowses.
*/
static inline gboolean
-render_line_horizontal (HDC hdc,
+render_line_horizontal (GdkGCWin32 *gcwin32,
int x1,
int x2,
- int y,
- int pen_width,
- DWORD *dashes,
- int num_dashes)
+ int y)
{
- int n;
+ int n;
+ HDC hdc = gcwin32->hdc;
+ int pen_width = gcwin32->pen_width;
+ DWORD *dashes;
+ int num_dashes;
+ int _x1 = x1;
+
+ if (gcwin32->pen_dashes)
+ {
+ dashes = gcwin32->pen_dashes;
+ num_dashes = gcwin32->pen_num_dashes;
+ x1 += gcwin32->pen_dash_offset;
+ }
+ else
+ {
+ dashes = default_double_dashes;
+ num_dashes = G_N_ELEMENTS (default_double_dashes);
+ }
for (n = 0; x1 < x2; n++)
{
x1 += dashes[n % num_dashes];
}
+ if (gcwin32->pen_double_dash)
+ {
+ HBRUSH hbr;
+
+ if ((hbr = SelectObject (hdc, gcwin32->pen_hbrbg)) == HGDI_ERROR)
+ return FALSE;
+ x1 = _x1;
+ if (gcwin32->pen_dashes)
+ x1 += gcwin32->pen_dash_offset;
+ for (n = 0; x1 < x2; n++)
+ {
+ int len = dashes[n % num_dashes];
+ if (x1 + len > x2)
+ len = x2 - x1;
+
+ if (n % 2)
+ if (!GDI_CALL (PatBlt, (hdc, x1, y - pen_width / 2,
+ len, pen_width,
+ PATCOPY)))
+ return FALSE;
+
+ x1 += dashes[n % num_dashes];
+ }
+ if (SelectObject (hdc, hbr) == HGDI_ERROR)
+ return FALSE;
+ }
+
return TRUE;
}
static inline gboolean
-render_line_vertical (HDC hdc,
+render_line_vertical (GdkGCWin32 *gcwin32,
int x,
int y1,
- int y2,
- int pen_width,
- DWORD *dashes,
- int num_dashes)
+ int y2)
{
- int n;
+ int n;
+ HDC hdc = gcwin32->hdc;
+ int pen_width = gcwin32->pen_width;
+ DWORD *dashes;
+ int num_dashes;
+ int _y1 = y1;
+
+ if (gcwin32->pen_dashes)
+ {
+ dashes = gcwin32->pen_dashes;
+ num_dashes = gcwin32->pen_num_dashes;
+ y1 += gcwin32->pen_dash_offset;
+ }
+ else
+ {
+ dashes = default_double_dashes;
+ num_dashes = G_N_ELEMENTS (default_double_dashes);
+ }
for (n = 0; y1 < y2; n++)
{
y1 += dashes[n % num_dashes];
}
+ if (gcwin32->pen_double_dash)
+ {
+ HBRUSH hbr;
+
+ if ((hbr = SelectObject (hdc, gcwin32->pen_hbrbg)) == HGDI_ERROR)
+ return FALSE;
+ y1 = _y1;
+ if (gcwin32->pen_dashes)
+ y1 += gcwin32->pen_dash_offset;
+ for (n = 0; y1 < y2; n++)
+ {
+ int len = dashes[n % num_dashes];
+ if (y1 + len > y2)
+ len = y2 - y1;
+ if (n % 2)
+ if (!GDI_CALL (PatBlt, (hdc, x - pen_width / 2, y1,
+ pen_width, len,
+ PATCOPY)))
+ return FALSE;
+
+ y1 += dashes[n % num_dashes];
+ }
+ if (SelectObject (hdc, hbr) == HGDI_ERROR)
+ return FALSE;
+ }
+
return TRUE;
}
x -= x_offset;
y -= y_offset;
- if (!filled && gcwin32->pen_dashes && !G_WIN32_IS_NT_BASED ())
+ if (!filled && (gcwin32->pen_double_dash ||
+ (gcwin32->pen_dashes && (gcwin32->pen_dash_offset ||
+ !G_WIN32_IS_NT_BASED ()))))
{
- render_line_vertical (hdc, x, y, y+height+1,
- gcwin32->pen_width,
- gcwin32->pen_dashes,
- gcwin32->pen_num_dashes) &&
- render_line_horizontal (hdc, x, x+width+1, y,
- gcwin32->pen_width,
- gcwin32->pen_dashes,
- gcwin32->pen_num_dashes) &&
- render_line_vertical (hdc, x+width+1, y, y+height+1,
- gcwin32->pen_width,
- gcwin32->pen_dashes,
- gcwin32->pen_num_dashes) &&
- render_line_horizontal (hdc, x, x+width+1, y+height+1,
- gcwin32->pen_width,
- gcwin32->pen_dashes,
- gcwin32->pen_num_dashes);
+ render_line_vertical (gcwin32, x, y, y+height+1) &&
+ render_line_horizontal (gcwin32, x, x+width+1, y) &&
+ render_line_vertical (gcwin32, x+width+1, y, y+height+1) &&
+ render_line_horizontal (gcwin32, x, x+width+1, y+height+1);
}
else
{
region = widen_bounds (&bounds, GDK_GC_WIN32 (gc)->pen_width);
generic_draw (drawable, gc,
- GDK_GC_FOREGROUND | (filled ? 0 : LINE_ATTRIBUTES),
+ GDK_GC_FOREGROUND | GDK_GC_BACKGROUND |
+ (filled ? 0 : LINE_ATTRIBUTES),
draw_rectangle, region, filled, x, y, width, height);
gdk_region_destroy (region);
}
}
- if (gcwin32->pen_dashes && !G_WIN32_IS_NT_BASED ())
+ if (gcwin32->pen_double_dash ||
+ (gcwin32->pen_dashes && (gcwin32->pen_dash_offset ||
+ !G_WIN32_IS_NT_BASED ())))
{
for (i = 0; i < nsegs; i++)
{
else
y1 = segs[i].y2, y2 = segs[i].y1;
- render_line_vertical (hdc,
- segs[i].x1, y1, y2,
- gcwin32->pen_width,
- gcwin32->pen_dashes,
- gcwin32->pen_num_dashes);
+ render_line_vertical (gcwin32, segs[i].x1, y1, y2);
}
else if (segs[i].y1 == segs[i].y2)
{
else
x1 = segs[i].x2, x2 = segs[i].x1;
- render_line_horizontal (hdc,
- x1, x2, segs[i].y1,
- gcwin32->pen_width,
- gcwin32->pen_dashes,
- gcwin32->pen_num_dashes);
+ render_line_horizontal (gcwin32, x1, x2, segs[i].y1);
}
else
GDI_CALL (MoveToEx, (hdc, segs[i].x1, segs[i].y1, NULL)) &&
region = widen_bounds (&bounds, GDK_GC_WIN32 (gc)->pen_width);
- generic_draw (drawable, gc, GDK_GC_FOREGROUND|LINE_ATTRIBUTES,
+ generic_draw (drawable, gc, GDK_GC_FOREGROUND | GDK_GC_FOREGROUND |
+ LINE_ATTRIBUTES,
draw_segments, region, segs, nsegs);
gdk_region_destroy (region);
pts[i].y -= y_offset;
}
- if (gcwin32->pen_dashes && !G_WIN32_IS_NT_BASED ())
+ if (gcwin32->pen_double_dash ||
+ (gcwin32->pen_dashes && (gcwin32->pen_dash_offset ||
+ !G_WIN32_IS_NT_BASED ())))
{
for (i = 0; i < npoints - 1; i++)
{
else
y1 = pts[i].y, y2 = pts[i+1].y;
- render_line_vertical (hdc, pts[i].x, y1, y2,
- gcwin32->pen_width,
- gcwin32->pen_dashes,
- gcwin32->pen_num_dashes);
+ render_line_vertical (gcwin32, pts[i].x, y1, y2);
}
else if (pts[i].y == pts[i+1].y)
{
else
x1 = pts[i].x, x2 = pts[i+1].x;
- render_line_horizontal (hdc, x1, x2, pts[i].y,
- gcwin32->pen_width,
- gcwin32->pen_dashes,
- gcwin32->pen_num_dashes);
+ render_line_horizontal (gcwin32, x1, x2, pts[i].y);
}
else
GDI_CALL (MoveToEx, (hdc, pts[i].x, pts[i].y, NULL)) &&
region = widen_bounds (&bounds, GDK_GC_WIN32 (gc)->pen_width);
- generic_draw (drawable, gc, GDK_GC_FOREGROUND|LINE_ATTRIBUTES,
+ generic_draw (drawable, gc, GDK_GC_FOREGROUND | GDK_GC_BACKGROUND |
+ LINE_ATTRIBUTES,
draw_lines, region, pts, npoints);
gdk_region_destroy (region);
}
win32_gc->pen_style &= ~(PS_STYLE_MASK);
win32_gc->pen_style |= PS_SOLID;
+ win32_gc->pen_double_dash = FALSE;
break;
case GDK_LINE_ON_OFF_DASH:
case GDK_LINE_DOUBLE_DASH:
win32_gc->pen_style &= ~(PS_STYLE_MASK);
win32_gc->pen_style |= PS_DASH;
}
+ win32_gc->pen_double_dash = values->line_style == GDK_LINE_DOUBLE_DASH;
break;
}
GDK_NOTE (GC, (g_print ("%sps|=PS_STYLE_%s", s, _gdk_win32_psstyle_to_string (win32_gc->pen_style)),
win32_gc->pen_style = PS_GEOMETRIC|PS_ENDCAP_FLAT|PS_JOIN_MITER;
win32_gc->pen_dashes = NULL;
win32_gc->pen_num_dashes = 0;
+ win32_gc->pen_dash_offset = 0;
+ win32_gc->pen_double_dash = FALSE;
+ win32_gc->pen_hbrbg = NULL;
win32_gc->values_mask = GDK_GC_FUNCTION | GDK_GC_FILL;
if (win32_gc->pen_style & PS_SOLID)
values->line_style = GDK_LINE_SOLID;
else if (win32_gc->pen_style & PS_DASH)
- values->line_style = GDK_LINE_ON_OFF_DASH;
+ values->line_style = win32_gc->pen_double_dash ? GDK_LINE_DOUBLE_DASH :
+ GDK_LINE_ON_OFF_DASH;
else
values->line_style = GDK_LINE_SOLID;
win32_gc->pen_dashes = g_new (DWORD, n);
for (i = 0; i < n; i++)
win32_gc->pen_dashes[i] = dash_list[i];
+ win32_gc->pen_dash_offset = dash_offset;
}
void
dst_win32_gc->pen_dashes = g_memdup (src_win32_gc->pen_dashes,
sizeof (DWORD) * src_win32_gc->pen_num_dashes);
dst_win32_gc->pen_num_dashes = src_win32_gc->pen_num_dashes;
+ dst_win32_gc->pen_dash_offset = src_win32_gc->pen_dash_offset;
+ dst_win32_gc->pen_double_dash = src_win32_gc->pen_double_dash;
dst_win32_gc->hdc = NULL;
dst_win32_gc->saved_dc = FALSE;
dst_win32_gc->hwnd = NULL;
dst_win32_gc->holdpal = NULL;
+ dst_win32_gc->pen_hbrbg = NULL;
}
GdkScreen *
}
}
-static COLORREF
-predraw_set_foreground (GdkGC *gc,
- GdkColormap *colormap,
- gboolean *ok)
+gboolean
+predraw (GdkGC *gc,
+ GdkColormap *colormap)
{
- COLORREF fg;
GdkGCWin32 *win32_gc = (GdkGCWin32 *) gc;
GdkColormapPrivateWin32 *colormap_private;
gint k;
+ gboolean ok = TRUE;
if (colormap &&
(colormap->visual->type == GDK_VISUAL_PSEUDO_COLOR ||
g_assert (colormap_private != NULL);
if (!(win32_gc->holdpal = SelectPalette (win32_gc->hdc, colormap_private->hpal, FALSE)))
- WIN32_GDI_FAILED ("SelectPalette"), *ok = FALSE;
+ WIN32_GDI_FAILED ("SelectPalette"), ok = FALSE;
else if ((k = RealizePalette (win32_gc->hdc)) == GDI_ERROR)
- WIN32_GDI_FAILED ("RealizePalette"), *ok = FALSE;
+ WIN32_GDI_FAILED ("RealizePalette"), ok = FALSE;
else if (k > 0)
- GDK_NOTE (COLORMAP, g_print ("predraw_set_foreground: realized %p: %d colors\n",
+ GDK_NOTE (COLORMAP, g_print ("predraw: realized %p: %d colors\n",
colormap_private->hpal, k));
}
- fg = _gdk_win32_colormap_color (colormap, win32_gc->foreground);
-
- GDK_NOTE (GC, g_print ("predraw_set_foreground: fg=%06lx\n", fg));
- return fg;
+ return ok;
}
/**
GdkGCWin32 *win32_gc = (GdkGCWin32 *) gc;
GdkDrawableImplWin32 *impl = NULL;
gboolean ok = TRUE;
- COLORREF fg = RGB (0, 0, 0);
+ COLORREF fg = RGB (0, 0, 0), bg = RGB (255, 255, 255);
LOGBRUSH logbrush;
HPEN hpen;
HBRUSH hbr;
if (ok && (win32_gc->saved_dc = SaveDC (win32_gc->hdc)) == 0)
WIN32_GDI_FAILED ("SaveDC");
}
-
+
+ if (ok && (usage & (GDK_GC_FOREGROUND | GDK_GC_BACKGROUND)))
+ ok = predraw (gc, impl->colormap);
+
if (ok && (usage & GDK_GC_FOREGROUND))
{
- fg = predraw_set_foreground (gc, impl->colormap, &ok);
- if (ok && (hbr = CreateSolidBrush (fg)) == NULL)
+ fg = _gdk_win32_colormap_color (impl->colormap, win32_gc->foreground);
+ if ((hbr = CreateSolidBrush (fg)) == NULL)
WIN32_GDI_FAILED ("CreateSolidBrush"), ok = FALSE;
if (ok && SelectObject (win32_gc->hdc, hbr) == NULL)
if (ok && (usage & LINE_ATTRIBUTES))
{
- /* Create and select pen */
- logbrush.lbStyle = BS_SOLID;
- logbrush.lbColor = fg;
- logbrush.lbHatch = 0;
-
- if (win32_gc->pen_num_dashes > 0 && !G_WIN32_IS_NT_BASED ())
- {
- /* The Win9x GDI is rather limited so we either draw dashed
- * lines ourselves (only horizontal and vertical) or let them be
- * drawn solid to avoid implementing a whole line renderer.
- */
- if ((hpen = ExtCreatePen (
- (win32_gc->pen_style & ~(PS_STYLE_MASK)) | PS_SOLID,
- MAX (win32_gc->pen_width, 1),
- &logbrush,
- 0, NULL)) == NULL)
- WIN32_GDI_FAILED ("ExtCreatePen"), ok = FALSE;
- }
- else
- {
- if ((hpen = ExtCreatePen (win32_gc->pen_style,
- MAX (win32_gc->pen_width, 1),
- &logbrush,
- win32_gc->pen_num_dashes,
- win32_gc->pen_dashes)) == NULL)
- WIN32_GDI_FAILED ("ExtCreatePen"), ok = FALSE;
+ /* For drawing GDK_LINE_DOUBLE_DASH */
+ if ((usage & GDK_GC_BACKGROUND) && win32_gc->pen_double_dash)
+ {
+ bg = _gdk_win32_colormap_color (impl->colormap, win32_gc->background);
+ if ((win32_gc->pen_hbrbg = CreateSolidBrush (bg)) == NULL)
+ WIN32_GDI_FAILED ("CreateSolidBrush"), ok = FALSE;
+ }
+
+ if (ok)
+ {
+ /* Create and select pen */
+ logbrush.lbStyle = BS_SOLID;
+ logbrush.lbColor = fg;
+ logbrush.lbHatch = 0;
+
+ if (win32_gc->pen_num_dashes > 0 && !G_WIN32_IS_NT_BASED ())
+ {
+ /* The Win9x GDI is rather limited so we either draw dashed
+ * lines ourselves (only horizontal and vertical) or let them be
+ * drawn solid to avoid implementing a whole line renderer.
+ */
+ if ((hpen = ExtCreatePen (
+ (win32_gc->pen_style & ~(PS_STYLE_MASK)) | PS_SOLID,
+ MAX (win32_gc->pen_width, 1),
+ &logbrush,
+ 0, NULL)) == NULL)
+ WIN32_GDI_FAILED ("ExtCreatePen"), ok = FALSE;
+ }
+ else
+ {
+ if ((hpen = ExtCreatePen (win32_gc->pen_style,
+ MAX (win32_gc->pen_width, 1),
+ &logbrush,
+ win32_gc->pen_num_dashes,
+ win32_gc->pen_dashes)) == NULL)
+ WIN32_GDI_FAILED ("ExtCreatePen"), ok = FALSE;
+ }
+
+ if (ok && SelectObject (win32_gc->hdc, hpen) == NULL)
+ WIN32_GDI_FAILED ("SelectObject"), ok = FALSE;
}
-
- if (ok && SelectObject (win32_gc->hdc, hpen) == NULL)
- WIN32_GDI_FAILED ("SelectObject"), ok = FALSE;
}
if (ok && (usage & GDK_GC_FONT))
if (hbr != NULL)
GDI_CALL (DeleteObject, (hbr));
+ if (win32_gc->pen_hbrbg != NULL)
+ GDI_CALL (DeleteObject, (win32_gc->pen_hbrbg));
+
win32_gc->hdc = NULL;
}
DWORD pen_style;
DWORD *pen_dashes; /* use for PS_USERSTYLE or step-by-step rendering */
gint pen_num_dashes;
+ gint pen_dash_offset;
+ gboolean pen_double_dash;
+ HBRUSH pen_hbrbg;
/* Following fields are valid while the GC exists as a Windows DC */
HDC hdc;